package com.hehe.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hehe.powernode.constant.AuthConstants;
import com.hehe.powernode.constant.BusinessEnum;
import com.hehe.powernode.constant.HttpConstants;
import com.hehe.powernode.model.LoginResult;
import com.hehe.powernode.model.Result;
import com.hehe.strategy.impl.UserDetailsServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.UUID;
//@Order(99)
@Slf4j
@Order(1)  // 优先级较高，先执行认证逻辑
@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ObjectMapper objectMapper;


    /**
     * 1.1自定义的认证流程
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置security框架走自己的登录流程
        auth.userDetailsService(userDetailsService);
    }

    /**
     * 网络请求配置
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() // 确保 CSRF 保护在最前面禁用
                .cors().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .formLogin()
                .loginProcessingUrl(AuthConstants.LOGIN_URL)
                .successHandler(authenticationSuccessHandler())
                .failureHandler(authenticationFailureHandler())
                .and()
                .logout()
                .logoutUrl(AuthConstants.LOGIN_OUT)
                .logoutSuccessHandler(logoutSuccessHandler())
                .and()
                .authorizeRequests()
//                .antMatchers("/auth-server/doLogin").permitAll()
                .antMatchers("/doLogin").permitAll()
                .antMatchers("/test/list").permitAll()
                .antMatchers("/*.html").permitAll()
                .antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**").permitAll()
                .antMatchers("/sys/menu/nav").permitAll()
                .antMatchers("/test").permitAll()
                .anyRequest().authenticated()
                .and()
//                .addFilterBefore(tokenTranslationFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint())
                .accessDeniedHandler(accessDeniedHandler());
    }

    /**
     * 登录成功处理器
     * 1.生成一个token
     * 2.将当前的认证对象存入redis
     * 3.返回token
     *
     * @return
     */
    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            log.info("authenticationSuccessHandler ");
            // 设置响应信息
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding(HttpConstants.UTF_8);
            // 使用UUID生成token
            String token = UUID.randomUUID().toString();
            // 从Spring Security中获取用户身份信息，并转换为json字符串
            Object principal = authentication.getPrincipal();
            String userStr = objectMapper.writeValueAsString(principal);
            stringRedisTemplate.opsForValue().set(AuthConstants.LOGIN_TOKEN_PREFIX + token, userStr, Duration.ofSeconds(AuthConstants.TOKEN_TIME));
            // 封装登录响应对象
            LoginResult loginResult = new LoginResult(token, AuthConstants.TOKEN_TIME);
            // 返回结果
            String s = objectMapper.writeValueAsString(Result.success(loginResult));
            response.getWriter().write(s);
            response.getWriter().flush();
            response.getWriter().close();
        };
    }

    /**
     * 登录失败处理器
     */
    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return (request, response, exception) -> {
            log.info("authenticationFailureHandler ");
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding(HttpConstants.UTF_8); // 封装返回结果
            Result<String> result = new Result<>();
            result.setCode(BusinessEnum.UN_AUTHORIZATION.getCode());
            if (exception instanceof BadCredentialsException) {
                result.setMsg("用户名或密码有误");
            } else if (exception instanceof UsernameNotFoundException) {
                result.setMsg("用户名不存在");
            } else if (exception instanceof AccountExpiredException) {
                result.setMsg("帐号异常，请联系管理员");
            } else if (exception instanceof InternalAuthenticationServiceException) {
                result.setMsg(exception.getMessage());
            } else {
                result.setMsg(BusinessEnum.OPERATION_FAIL.getDesc());
            }
            // 返回结果对象
            ObjectMapper objectMapper = new ObjectMapper();
            String s = objectMapper.writeValueAsString(result);
            response.getWriter().write(s);
            response.getWriter().flush();
            response.getWriter().close();
        };
    }
    /**
     * 没有携带token处理器，直接返回401
     *
     * @return
     */
    private AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            log.error("authenticationEntryPoint ");
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);
            // 返回结果对象
            Result<String> result = Result.fail(BusinessEnum.UN_AUTHORIZATION);
            String s = objectMapper.writeValueAsString(result);
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }

    /**
     * 携带token权限不足处理器，直接返回403
     *
     * @return
     */
    private AccessDeniedHandler accessDeniedHandler() {
        return (request, response, authException) -> {
            log.info("accessDeniedHandler ");
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);
            // 返回结果对象
            Result<String> result = Result.fail(BusinessEnum.ACCESS_DENY_FAIL);
            String s = objectMapper.writeValueAsString(result);
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }
    /**
     * 登出成功的处理流程
     */
    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        return (request, response, exception) -> {
            log.info("logoutSuccessHandler ");
            response.setContentType("application/json;charset=utf-8");
            response.setCharacterEncoding(HttpConstants.UTF_8); // 封装返回结果

            Result<String> result = Result.success(null);
            ObjectMapper objectMapper = new ObjectMapper();
            String s = objectMapper.writeValueAsString(result);

            result.setCode(BusinessEnum.UN_AUTHORIZATION.getCode());
            String authorization = request.getHeader(AuthConstants.AUTHORIZATION);
            String token = authorization.replaceFirst(AuthConstants.BEARER,"");
            stringRedisTemplate.delete(AuthConstants.LOGIN_TOKEN_PREFIX+token);
            // 返回结果对象
            response.getWriter().write(s);
            response.getWriter().flush();
            response.getWriter().close();

        };
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
